import * as moment from 'moment';
import { UInfoModel } from './uuid.model';
import { element } from 'protractor';
import { NzMessageService } from 'ng-zorro-antd';


export class ExceptDateModel {
  public exceptDate: {
    name: string,
    startDate: number,
    endDate: number
  }[];
}

export class EditModel {
  public relations: PredecessorLinkModel[];
  public taskName: string;
  public showDuration: number;
  public constructor(param) {
    (param.relations) && (this.relations = param.relations);
    (param.taskName) && (this.taskName = param.taskName);
    (param.showDuration) && (this.showDuration = param.showDuration);
  }
}



export class GanttModel extends ExceptDateModel {
  /**
   * 公用参数
   */
  public id: number;
  public symbol: number;
  public sqId: string;
  public uid: number;
  public wbs: string | any;
  public taskName: string;
  public IsSelected = false;
  public step = 0;

  public childTaskID: any[] = [];
  public parentTaskID: number = null;

  public level = 1;
  public isFold = false;
  public ganttChartId: string;
  public defaultData = null;
  public bindings: UInfoModel[];
  public allFinished = false;
  public isMilepost = false;
  public prevRelation: PredecessorLinkModel[];

  public isDelay = false;

  private _exceptDuration = 0;
  public get exceptDuration() {
    return this._exceptDuration;
  }

  public set exceptDuration(value) {
    this._exceptDuration = value;
  }

  private _exceptActualDuration = 0;
  public get exceptActualDuration() {
    return this._exceptActualDuration;
  }

  public set exceptActualDuration(value) {
    // 实际时间
    if (this._actualDuration) {
      this.showActualDuration = this._actualDuration - value;
    } else {
      if (this._actualStartDate && this._actualEndDate) {
        let num = moment(this._actualEndDate).clone().diff(moment(this._actualStartDate), 'days');
        this.showActualDuration = num + 1;
      }
    }
    this._exceptActualDuration = value;
  }

  private _finishRate = 0;
  public get finishRate() {
    let finish = [];
    if (this.bindings.length > 0) {
      this.bindings.forEach((element) => {
        if (element.isFinished) {
          finish.push(element);
        }
      });
      if (finish.length > 0) {
        this._finishRate = finish.length / this.bindings.length;
      }else {
        this._finishRate = 0;
      }
    }
    if (this._finishRate === 1) {
      this.allFinished = true;
    }
    return this._finishRate;
  }
  public set finishRate(value) {
    if (value == 1) {
      this.allFinished = true;
    }
    this._finishRate = value;
  }

  /**
   * 计划参数
   */
  public truePrevTaskID: any;
  public isKey = false;
  public laterChildId: number = null;
  public earlierChildId: number = null;
  private _startDate = null;
  public get startDate() {
    return this._startDate;
  }
  public set startDate(value) {
    console.log(value)
    if (this.childTaskID.length <= 0 && value) {
      value = this.handleStartDate(value);
    }
    this._startDate = value;
  }

  private _duration;
  public get duration() {
    if (this._startDate && this._endDate) {
      let num = moment(this._endDate).clone().diff(moment(this._startDate), 'days');
      this._duration = num + 1;
    }
    return this._duration ? this._duration : 0;
  }
  public set duration(value) {
    if (this.childTaskID.length == 0 && value) {
      value = this.handleDuration(parseInt(value));
    } else {
      value = moment(this._endDate).clone().diff(moment(this._startDate), 'days') + 1;
    }
    this._duration = value;
  }
  private _endDate = null;
  public get endDate() {
    return this._endDate;
  }
  public set endDate(value) {
    if (this.childTaskID.length == 0 && value) {
      value = this.handleEndDate(value);
    }
    this._endDate = value;
  }

  private _showDuration: number;
  public get showDuration() {
    return this._showDuration ? this._showDuration : 0;
  }
  public set showDuration(value) {
    this._showDuration = value;
  }


  public showActualDuration: number;
  /**
   * 实际参数
   */
  public actulaTruePrevTaskID: any;
  public isActualKey = false;
  public acLaterChildId: number = null;
  public acEarlierChildId: number = null;
  private _actualStartDate: any = null;
  public get actualStartDate() {
    return this._actualStartDate;
  }
  public set actualStartDate(value) {
    if (this.childTaskID.length == 0 && value) {
      value = this.handleActualStartDate(value);
    }
    this._actualStartDate = value;
  }

  private _actualDuration: any = null;
  public get actualDuration() {
    if (this._actualStartDate && this._actualEndDate) {
      let num = moment(this._actualEndDate).clone().diff(moment(this._actualStartDate), 'days');
      this._actualDuration = num + 1;
    }
    return this._actualDuration;
  }
  public set actualDuration(value) {
    if (this.childTaskID.length == 0 && value) {
      value = this.handleActualDuration(value);
    }
    this._actualDuration = value;
  }

  private _actualEndDate: any = null;
  public get actualEndDate() {
    return this._actualEndDate;
  }
  public set actualEndDate(value) {
    // if (this.childTaskID.length == 0 && value) {
    //   value = this.handleActualEndDate(value)
    // }
    this._actualEndDate = value;
  }


  public constructor(param: any) {
    super();
    // 数据库id
    (param.sqId) && (this.sqId = param.sqId);
    // UID
    (param.uid) && (this.uid = param.uid);
    // 标识符--orderId
    (param.id) && (this.id = param.id);
    // 标识符--对接模型
    (param.symbol) && (this.symbol = param.symbol);
    // 所属甘特图id
    (param.ganttChartId) && (this.ganttChartId = param.ganttChartId);
    // 所属甘特图id
    (param.wbs) && (this.wbs = param.wbs);
    // 任务名称
    (param.taskName) && (this.taskName = param.taskName);
    // 是否被选中
    (param.IsSelected) && (this.IsSelected = param.IsSelected);
    // 计划开始时间
    (param.startDate) && (this.startDate = param.startDate);
    // 计划工期
    (param.duration) && (this.duration = param.duration);
    // 计划完成时间
    (param.endDate) && (this.endDate = param.endDate);
    // 实际开始时间
    (param.actualStartDate) && (this.actualStartDate = param.actualStartDate);
    // 实际工期
    (param.actualDuration) && (this.actualDuration = param.actualDuration);
    // 实际完成时间
    (param.actualEndDate) && (this.actualEndDate = param.actualEndDate);
    // 前置任务（已废弃）
    // (param.prevTask) && (this.prevTask = param.prevTask);
    // 紧前任务
    (param.truePrevTaskID) && (this.truePrevTaskID = param.truePrevTaskID);
    // 是否是关键任务
    (param.isKey) && (this.isKey = param.isKey);
    // 子任务id
    (param.childTaskID) && (this.childTaskID = param.childTaskID);
    // 父任务id
    (param.parentTaskID) && (this.parentTaskID = param.parentTaskID);
    // 级别
    (param.level) && (this.level = param.level);
    // 绑定的构件
    (param.bindings) && (this.bindings = param.bindings);
    // 是否是里程碑
    (param.isMilepost) && (this.isMilepost = param.isMilepost);
    // 完成率
    (param.finishRate !== null) && (this.finishRate = param.finishRate);
    // 前置任务
    (param.prevRelation) && (this.prevRelation = param.prevRelation);
    // 所属甘特图的额外日期
    (param.exceptDate) && (this.exceptDate = param.exceptDate);
    // 目前的状态
    (param.step) && (this.step = param.step);
    // 摘要任务下,影响摘要任务结束时间时间的任务
    (param.laterChildId) && (this.laterChildId = param.laterChildId);
    // 摘要任务下,影响摘要任务开始时间的任务
    (param.earlierChildId) && (this.earlierChildId = param.earlierChildId);
    // 摘要任务下,影响摘要任务结束时间时间的任务
    (param.acLaterChildId) && (this.acLaterChildId = param.acLaterChildId);
    // 摘要任务下,影响摘要任务开始时间的任务
    (param.acEarlierChildId) && (this.acEarlierChildId = param.acEarlierChildId);



    // 任务中的额外日期工期
    (param.exceptDuration) && (this.exceptDuration = param.exceptDuration);
    // 任务中的额外日期工期
    (param.exceptActualDuration) && (this.exceptActualDuration = param.exceptActualDuration);
    // 任务显示的工期
    (param.showDuration) && (this.showDuration = param.showDuration);
    // 任务显示的实际工期
    (param.showActualDuration) && (this.showActualDuration = param.showActualDuration);

    // 是否延期
    // (param.isDelay) && (this.isDelay = param.isDelay);
  }

  public toJson() {
    return {
      orderId: this.id,
      ganttChartId: this.ganttChartId,
      taskName: this.taskName,
      startAt: this.startDate ? moment(this.startDate).unix() : null,
      finishAt: this.endDate ? moment(this.endDate).unix() : null,
      duration: this.duration,
      actualStartAt: this.actualStartDate ? moment(this.actualStartDate).unix() : null,
      actualFinishAt: this.actualEndDate == 1 ? moment(this.actualEndDate).unix() : null,
      parentTaskId: this.parentTaskID,
      preTask: JSON.stringify(this.prevRelation),
      childTaskID: this.childTaskID,
      level: this.level,
      bindings: this.bindings,
      milestone: this.isMilepost ? 1 : 0,
      finishRate: this.finishRate,
      step: this.step
      // sqlStartDate: this.sqlStartDate ? moment(this.sqlStartDate).unix() : null,
      // sqlEndDate: this.sqlEndDate ? moment(this.sqlEndDate).unix() : null,
      // sqlDuration: this.sqlDuration,
      // sqlActualStartDate: this.sqlActualStartDate,
      // sqlActualEndDate: this.sqlActualEndDate,
      // sqlActualDuration: this.sqlActualDuration,
    };
  }

  public toEditJson() {
    return {
      id: this.sqId,
      orderId: this.id,
      ganttChartId: this.ganttChartId,
      taskName: this.taskName,
      startAt: this.startDate ? moment(this.startDate).unix() : null,
      finishAt: this.endDate ? moment(this.endDate).unix() : null,
      duration: this.duration,
      actualStartAt: this.actualStartDate ? moment(this.actualStartDate).unix() : null,
      actualFinishAt: this.actualEndDate ? moment(this.actualEndDate).unix() : null,
      parentTaskId: this.parentTaskID,
      preTask: JSON.stringify(this.prevRelation),
      childTaskID: this.childTaskID,
      level: this.level,
      bindings: this.bindings,
      milestone: this.isMilepost ? 1 : 0,
      finishRate: this.finishRate,
      step: this.step
      // sqlStartDate: this.sqlStartDate ? moment(this.sqlStartDate).unix() : null,
      // sqlEndDate: this.sqlEndDate ? moment(this.sqlEndDate).unix() : null,
      // sqlDuration: this.sqlDuration,
      // sqlActualStartDate: this.sqlActualStartDate ? moment(this.sqlActualStartDate).unix() : null,
      // sqlActualEndDate: this.sqlActualEndDate ? moment(this.sqlActualEndDate).unix() : null,
      // sqlActualDuration: this.sqlActualDuration ? moment(this.sqlActualDuration).unix() : null,
    };
  }

  public toMpp() {
    console.log(this.startDate)
    return {
      Id: this.sqId,  //数据库id
      _ID: this.id, // orderid
      UID: this.uid,
      ParentId: this.ganttChartId,
      Name: this.taskName,
      Start: this.startDate ? moment(this.startDate).toJSON() : null,
      Finish: this.endDate ? moment(this.endDate).toJSON() : null,
      Duration: `PT${this.duration * 8}H0M0S`,
      ActualStart: this.actualStartDate ? moment(this.actualStartDate).toJSON() : null,
      ActualFinish: this.actualEndDate ? moment(this.actualEndDate).toJSON() : null,
      WBS: this.wbs,
      Milestone: this.isMilepost
    };
  }

  public handleStartDate(startDate) {
    let unix = startDate ? moment(startDate).unix() : null;
    let endDate = this._endDate;
    let duration = this._duration;
    if (this.exceptDate && this.exceptDate.length > 0) {
      this.exceptDate.forEach((item) => {
        if (unix <= item.endDate && unix >= item.startDate) {
          // 如果所选s在额外日期之间，d不变，e=s+d
          // let errorDate = moment(startDate).format('MM/DD');
          let correct = moment.unix(item.endDate).clone().add(1, 'days').toDate();
          // GanttModel.message.confirm('warning', `任务${this.id}的计划开始时间${errorDate}为非工作日，将移动该任务开始时间到下一工作日${correct.format('MM/DD')}。`, 10000);
          startDate = correct;
        }
      });
    }
    if (!endDate) {
      if (duration && duration > 0) {
        this._endDate = moment(startDate).add(duration - 1, 'days').toDate();
      } else {
        this._endDate = startDate;
      }
    } else {
      this._endDate = moment(startDate).add(duration - 1, 'days').toDate();
    }
    return startDate;
  }

  public handleEndDate(endDate) {
    let unix = endDate ? moment(endDate).unix() : null;
    let startDate = this._startDate;
    let duration = this._duration;
    let startUnix = moment(this._startDate).unix();
    if (this.exceptDate && this.exceptDate.length > 0) {
      // 有额外日期
      this.exceptDate.forEach((item) => {
        if (unix <= item.endDate && unix >= item.startDate) {
          // 所选endDate在额外日期之间，e自动延至额外日期结束后一天，s不变，d=e-s
          let errorDate = moment(endDate).format('MM/DD');
          let correct = moment.unix(item.endDate).clone().add(1, 'days');
          // GanttModel.message.confirm('warning', `任务${this.id}的计划结束时间${errorDate}为非工作日，将移动该任务结束时间到下一工作日${correct.format('MM/DD')}。`, 10000);
          this._exceptDuration = moment.unix(item.endDate).clone().diff(moment.unix(item.startDate), 'days') + 1;
          endDate = correct;
        }
      });
    }
    if (!startDate) {
      if (duration && duration > 0) {
        // 没s，有d
        this._startDate = moment(endDate).clone().subtract(duration - 1, 'days').toDate();
      } else {
        // 没s，没d
        this._startDate = endDate;
      }
    } else {
      if (moment(endDate).isBefore(moment(startDate))) {
        this._startDate = moment(endDate).subtract(duration - 1, 'days').toDate();
      } else {
        this._duration = moment(endDate).clone().diff(moment(startDate), 'days') + 1;
      }
    }
    return endDate;
  }

  public handleDuration(duration) {
    if (this._startDate && this._endDate) {
      if (duration > 0) {
        let endDate = moment(this._startDate).add(duration - 1, 'days').toDate();
        let endUnix = moment(endDate).unix();
        let startUnix = moment(this._startDate).unix();
        if (this.exceptDate && this.exceptDate.length > 0) {
          this.exceptDate.forEach((item) => {
            if (endUnix <= item.endDate && endUnix >= item.startDate) {
              // 结束时间在额外日期之间
              let errorDate = moment(endDate).format('MM/DD');
              let correct = moment.unix(item.endDate).clone().add(1, 'days');
              // GanttModel.message.confirm('warning', `所选日期${errorDate}为非工作日，将移动该任务结束时间到下一工作日${correct.format('MM/DD')}。`, 10000);
              this._exceptDuration = moment.unix(item.endDate).clone().diff(moment.unix(item.startDate), 'days') + 1;
              this._endDate = correct;
            } else {
              this._endDate = endDate;
            }
            // else if (startUnix <= item.startDate && endUnix >= item.endDate){
            //   // 如果任务中间有额外日期
            //   let exceptDuration = moment.unix(item.endDate).clone().diff(moment.unix(item.startDate), 'days') + 1;
            //   this._exceptDuration = exceptDuration;
            //   this._endDate = moment(this._startDate).add(duration + exceptDuration, 'days');
            // }
          });
        } else {
          this._endDate = endDate;
        }
        this._endDate = endDate;
      }
    }
    return duration;
  }

  public handleActualStartDate(startDate) {
    let unix = startDate ? moment(startDate).unix() : null;
    let actualEndDate = this._actualEndDate;
    let duration = this._actualDuration;
    if (this.exceptDate && this.exceptDate.length > 0) {
      this.exceptDate.forEach((item) => {
        if (unix <= item.endDate && unix >= item.startDate) {
          // 如果所选s在额外日期之间，d不变，e=s+d
          let errorDate = moment(startDate).format('MM/DD');
          let correct = moment.unix(item.endDate).clone().add(1, 'days').toDate();
          // GanttModel.message.confirm('warning', `任务${this.id}的计划开始时间${errorDate}为非工作日，将移动该任务开始时间到下一工作日${correct.format('MM/DD')}。`, 10000);
          startDate = correct;
        }
      });
    }
    if (!actualEndDate) {
      if (duration && duration > 0) {
        //没有endDate,有duration
        this.actualEndDate = moment(startDate).add(duration - 1, 'days').toDate();
      } else {
        // 没有duration
        this._actualEndDate = startDate;
      }
    } else {
      this.actualEndDate = moment(startDate).add(duration - 1, 'days').toDate();
    }
    return startDate;
  }

  public handleActualEndDate(endDate) {
    let unix = endDate ? moment(endDate).unix() : null;
    let startDate = this._actualStartDate;
    let duration = this._actualDuration;
    let startUnix = moment(this._actualStartDate).unix();
    if (this.exceptDate && this.exceptDate.length > 0) {
      // 有额外日期
      this.exceptDate.forEach((item) => {
        if (unix <= item.endDate && unix >= item.startDate) {
          // 所选endDate在额外日期之间，e自动延至额外日期结束后一天，s不变，d=e-s
          let errorDate = moment(endDate).format('MM/DD');
          let correct = moment.unix(item.endDate).clone().add(1, 'days').toDate();
          // GanttModel.message.confirm('warning', `任务${this.id}的计划结束时间${errorDate}为非工作日，将移动该任务结束时间到下一工作日${correct.format('MM/DD')}。`, 10000);
          this._exceptDuration = moment.unix(item.endDate).clone().diff(moment.unix(item.startDate), 'days') + 1;
          endDate = correct;
        }
      });
    }
    if (!startDate) {
      if (duration && duration > 0) {
        // 没s，有d
        this._actualStartDate = moment(endDate).clone().subtract(duration - 1, 'days').toDate();
      } else {
        // 没s，没d
        this._actualStartDate = endDate;
      }
    } else {
      if (moment(endDate).isBefore(moment(startDate))) {
        this._actualStartDate = moment(endDate).subtract(duration - 1, 'days').toDate();
      } else {
        this._actualDuration = moment(endDate).clone().diff(moment(startDate), 'days') + 1;
      }
    }
    return endDate;
  }

  public handleActualDuration(duration) {
    if (this._actualStartDate && this._actualEndDate) {
      if (duration > 0) {
        let endDate = moment(this._actualStartDate).add(duration - 1, 'days').toDate();
        this.endDate = endDate;
      }
    }
    return duration;
  }

}


export class PredecessorLinkModel {
  public id?: string;
  public prevId?: any;
  public relation: number;
  public delay = 0;
  public predecessorLink?: number;
  public defaultPerv?: any;
  public isDelete = 0;
  public parentId: string;
  public constructor(param) {
    (param.id) && (this.id = param.id);
    (param.prevId) && (this.prevId = param.prevId);
    (param.relation) && (this.relation = param.relation);
    (param.delay) && (this.delay = param.delay);
    (param.predecessorLink) && (this.predecessorLink = param.predecessorLink);
    (param.defaultPerv) && (this.defaultPerv = param.defaultPerv);
    (param.isDelete) && (this.isDelete = param.isDelete);
    (param.parentId) && (this.parentId = param.parentId);
  }
}

